{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "from keras.models import Sequential, Model\n",
    "from keras.layers import GlobalAveragePooling2D, Dense, Flatten, Dropout, ELU, BatchNormalization, Lambda, merge, MaxPooling2D, Input, Activation\n",
    "from keras.layers.convolutional import Convolution2D, Cropping2D\n",
    "from keras.utils.visualize_util import plot\n",
    "from keras.optimizers import Adam\n",
    "from keras.callbacks import Callback, RemoteMonitor\n",
    "import keras.backend as K"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## HomographyNet Model Architecture\n",
    "\n",
    "![alt text](./documentation_images/homographynet.png \"General HomogrophyNet Model Architecture\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## HomographyNet as reported in the paper has two different variants.\n",
    "\n",
    "1. The classification head model variant\n",
    "2. The regression head model variant\n",
    "\n",
    "![alt text](./documentation_images/twoheads.png \"HomogrophyNet Model Variants\")\n",
    "\n",
    "### The version we are going to implement is the Regression head variant!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def euclidean_distance(y_true, y_pred):\n",
    "    return K.sqrt(K.maximum(K.sum(K.square(y_pred - y_true), axis=-1, keepdims=True), K.epsilon()))\n",
    "\n",
    "def homography_regression_model():\n",
    "    input_shape=(128, 128, 2)\n",
    "    input_img = Input(shape=input_shape)\n",
    "     \n",
    "    x = Convolution2D(64, 3, 3, subsample=(1, 1), border_mode='same', name='conv1', activation='relu')(input_img)\n",
    "    x = Convolution2D(64, 3, 3, subsample=(1, 1), border_mode='same', name='conv2', activation='relu')(x)\n",
    "    x = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool1')(x)\n",
    "    \n",
    "    x = Convolution2D(64, 3, 3, subsample=(1, 1), border_mode='same', name='conv3', activation='relu')(x)\n",
    "    x = Convolution2D(64, 3, 3, subsample=(1, 1), border_mode='same', name='conv4', activation='relu')(x)\n",
    "    x = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool2')(x)\n",
    "   \n",
    "    x = Convolution2D(128, 3, 3, subsample=(1, 1), border_mode='same', name='conv5', activation='relu')(x)\n",
    "    x = Convolution2D(128, 3, 3, subsample=(1, 1), border_mode='same', name='conv6', activation='relu')(x)\n",
    "    x = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool3')(x)\n",
    "    \n",
    "    x = Convolution2D(128, 3, 3, subsample=(1, 1), border_mode='same', name='conv7', activation='relu')(x)\n",
    "    x = Convolution2D(128, 3, 3, subsample=(1, 1), border_mode='same', name='conv8', activation='relu')(x)\n",
    "    \n",
    "    x = Flatten()(x)\n",
    "    x = Dense(1024, name='FC1')(x)\n",
    "    out = Dense(8, name='loss')(x)\n",
    "    \n",
    "    model = Model(input=input_img, output=[out])\n",
    "    plot(model, to_file='HomegraphyNet_Regression.png', show_shapes=True)\n",
    "    \n",
    "    \n",
    "    model.compile(optimizer=Adam(lr=1e-3), loss=euclidean_distance)\n",
    "    return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "____________________________________________________________________________________________________\n",
      "Layer (type)                     Output Shape          Param #     Connected to                     \n",
      "====================================================================================================\n",
      "input_2 (InputLayer)             (None, 128, 128, 2)   0                                            \n",
      "____________________________________________________________________________________________________\n",
      "conv1 (Convolution2D)            (None, 128, 128, 64)  1216        input_2[0][0]                    \n",
      "____________________________________________________________________________________________________\n",
      "conv2 (Convolution2D)            (None, 128, 128, 64)  36928       conv1[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "pool1 (MaxPooling2D)             (None, 64, 64, 64)    0           conv2[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "conv3 (Convolution2D)            (None, 64, 64, 64)    36928       pool1[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "conv4 (Convolution2D)            (None, 64, 64, 64)    36928       conv3[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "pool2 (MaxPooling2D)             (None, 32, 32, 64)    0           conv4[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "conv5 (Convolution2D)            (None, 32, 32, 128)   73856       pool2[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "conv6 (Convolution2D)            (None, 32, 32, 128)   147584      conv5[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "pool3 (MaxPooling2D)             (None, 16, 16, 128)   0           conv6[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "conv7 (Convolution2D)            (None, 16, 16, 128)   147584      pool3[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "conv8 (Convolution2D)            (None, 16, 16, 128)   147584      conv7[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "flatten_2 (Flatten)              (None, 32768)         0           conv8[0][0]                      \n",
      "____________________________________________________________________________________________________\n",
      "FC1 (Dense)                      (None, 1024)          33555456    flatten_2[0][0]                  \n",
      "____________________________________________________________________________________________________\n",
      "loss (Dense)                     (None, 8)             8200        FC1[0][0]                        \n",
      "====================================================================================================\n",
      "Total params: 34,192,264\n",
      "Trainable params: 34,192,264\n",
      "Non-trainable params: 0\n",
      "____________________________________________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model = homography_regression_model()\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  },
  "widgets": {
   "state": {},
   "version": "1.1.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
